/****************************************************************************
*                                                                           *
* graphadapter.h															*
*                                                                           *
* ALaRI 2008												                *
*                                                                           *
****************************************************************************/
#pragma once

#if !defined(__GRAPHADAPTER_H)
#define __GRAPHADAPTER_H

/****************************************************************************
* Includes										                            *
****************************************************************************/
#include "graphnode.h"
#include "directedgraph.h"
#include "undirectedgraph.h"
#include <iostream>
#include <fstream>

#include "../../common/defs.h"
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <string>
#include <map>


using namespace boost;

template <typename GraphType>
class CGraphAdapter
{
public :

	typedef typename GraphType::VertexProperty VertexProperty; 
	typedef typename GraphType::EdgeProperty EdgeProperty; 
	typedef typename GraphType::Graph Graph;
	
	typedef typename graph_traits<Graph const >::vertex_descriptor vertex_const_descriptor;
	typedef typename graph_traits<Graph const >::vertex_iterator vertex_const_iterator;
	typedef typename graph_traits<Graph const >::edge_descriptor edge_const_descriptor;

	typedef typename std::map<CGraphNode::NodeIDType, vertex_const_descriptor>::iterator map_vertex_id_iterator;
	typedef typename std::map<CGraphNode::NodeIDType, vertex_const_descriptor>::const_iterator map_vertex_id_const_iterator;

	CGraphAdapter(); 
	~CGraphAdapter(); 
	void addNode(const CGraphNode* pNode); 
	void writeGraphViz(std::string strFileName);
	void makeEdge(const CGraphNode *pNodeFrom, const CGraphNode *pNodeTo, int nWeight);

private :
	CGraphAdapter(const CGraphAdapter& adapter); 
	// data structure to store the graph
	Graph	*m_pGraph;
	// map verticies to nodes 
	std::map<CGraphNode::NodeIDType, vertex_const_descriptor> m_mapVertexID;

};

template <typename GraphType>
CGraphAdapter<GraphType>::CGraphAdapter()
	: m_pGraph(NULL)
{
	m_pGraph = new Graph();
	assert(NULL != m_pGraph);
}

template <typename GraphType>
CGraphAdapter<GraphType>::~CGraphAdapter()
{
	// cleara graph data
	SafeFree(m_pGraph);
}

template <typename GraphType>
void CGraphAdapter<GraphType>::addNode(const CGraphNode* pNode)
{
	// asserts
	assert(NULL != m_pGraph);
	assert(NULL != pNode);
	// delete node if it already exists
	map_vertex_id_iterator it = m_mapVertexID.find(pNode->getUniqueID());
	if (it != m_mapVertexID.end())
	{
		remove_vertex((*it).second, *m_pGraph);
		m_mapVertexID.erase(it);
	}
	// add new vertex
	std::string strName("Sr ");
	strName += pNode->stdStringName();
	vertex_const_descriptor vertex = add_vertex(strName, *m_pGraph);
	// map node to vertex
	m_mapVertexID[pNode->getUniqueID()] = vertex;
}

template <typename GraphType>
void CGraphAdapter<GraphType>::makeEdge(const CGraphNode *pNodeFrom, 
							  const CGraphNode *pNodeTo, int nWeight)
{
	vertex_const_descriptor vFrom = m_mapVertexID[pNodeFrom->getUniqueID()];
	vertex_const_descriptor vTo = m_mapVertexID[pNodeTo->getUniqueID()];
	// do not allow self loop 
	if (vFrom != vTo)
	{
		edge_const_descriptor edge; 
		bool bInserted;  
		tie(edge, bInserted) = add_edge(vFrom, vTo, nWeight, *m_pGraph);
	}
}

template <typename GraphType>
void CGraphAdapter<GraphType>::writeGraphViz(std::string strFileName)
{
	if (strFileName.empty())
		return; 
	std::ofstream fileGraph(strFileName.data(), std::ios::out | std::ios::trunc);
    if (!fileGraph)
    {
		std::cout << "Cannot open file. " << std::endl;
        assert(0);
    }
	typename property_map<Graph, vertex_name_t>::type namesVertex = get(vertex_name, *m_pGraph);
	typename property_map<Graph, edge_weight_t>::type wightEdges = get(edge_weight, *m_pGraph);
	write_graphviz(fileGraph, *m_pGraph, make_label_writer(namesVertex), make_label_writer(wightEdges));
	fileGraph.close();
}

#endif /* __GRAPHADAPTER_H */
/****************************************************************************
* End of file																*
****************************************************************************/